package com.kyz.speechsdk.engine;

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.SynthesizerListener;
import com.kyz.speechsdk.engine.abstracts.BaseUnderstandingEngine;
import com.kyz.speechsdk.engine.entity.EngineResult;
import com.kyz.speechsdk.ifly.AIUIManager;
import com.kyz.speechsdk.ifly.NLPResult;
import com.kyz.speechsdk.ifly.interfaces.IAIUIListener;
import com.kyz.speechsdk.ifly.interfaces.IRecognizeListener;
import com.kyz.speechsdk.ifly.interfaces.ISpeakListener;
import com.kyz.speechsdk.utlis.JsonParser;


import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.concurrent.Executors;

/**
 * create by ZhongZihao on 2020/12/29
 * 讯飞语义匹配
 */
public class IflyEngine extends BaseUnderstandingEngine {
    private static final String TAG = "TAG_IflyEngine";
    private HashMap<String, String> mRecogResults = new LinkedHashMap();
    private final Context context;
    private String iflyAppID = "";
    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    private String voicer = "xiaoyan";
    private String speed = "50";
    private String pitch = "50";
    private String volume = "30";
    private String vad_bos = "4000";
    private String vad_eos = "700";
    private String speech_timeout = "60000";
    private String net_timeout = "3000";
    private String s_language = "mandarin";
    private String pcm_path = "";

    private AIUIManager aiuiManager; //语义理解
    private SpeechRecognizer speechRecognizer;//语音听写
    private SpeechSynthesizer speechSynthesizer; //语音合成
    //当前语音合成监听回调
    private ISpeakListener startSpeakListener;
    private ISpeakListener lastStartSpeakListener;
    //全局语音合成进度监听
    private ISpeakListener mGlobalSpeakListener;
    private IRecognizeListener recognizeListener;


    private RecognizeTextCallback recognizeTextCallback;

    public interface RecognizeTextCallback {
        void onRecognizeText(String text);
    }

    public void setRecognizeTextCallback(RecognizeTextCallback recognizeTextCallback) {
        this.recognizeTextCallback = recognizeTextCallback;
    }


    private IflyEngine(Builder builder) {
        this.context = builder.context;
        if (!TextUtils.isEmpty(builder.iflyAppID)) {
            this.iflyAppID = builder.iflyAppID;
        }
        if (!TextUtils.isEmpty(builder.engineType)) {
            this.mEngineType = builder.engineType;
        }
        if (!TextUtils.isEmpty(builder.voicer)) {
            this.voicer = builder.voicer;
        }
        if (builder.speed >= 0 && builder.speed <= 100) {
            this.speed = Integer.toString(builder.speed);
        }
        if (builder.volume >= 0 && builder.volume <= 100) {
            this.volume = Integer.toString(builder.volume);
        }
        if (builder.pitch >= 0 && builder.pitch <= 100) {
            this.pitch = Integer.toString(builder.pitch);
        }
        if (builder.speech_timeout > 0) {
            this.speech_timeout = Integer.toString(builder.speech_timeout);
        }
        if (builder.net_timeout > 0) {
            this.net_timeout = Integer.toString(builder.net_timeout);
        }
        if (!TextUtils.isEmpty(builder.s_language)) {
            this.s_language = builder.s_language;
        }
        setNextEngine(builder.engine);
        createIfly();
    }

    private void createIfly() {
        SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + iflyAppID);
        speechRecognizer = SpeechRecognizer.createRecognizer(context, new InitListener() {
            @Override
            public void onInit(int code) {
                if (code != 0) {
                    Log.d(TAG, "初始化SpeechRecognizer失败，错误码：" + code);
                } else {
                    setDefaultRecognizeParam();
                }
            }
        });
        speechSynthesizer = SpeechSynthesizer.createSynthesizer(context, new InitListener() {
            @Override
            public void onInit(int code) {
                if (code != 0) {
                    Log.d(TAG, "初始化SpeechSynthesizer失败，错误码：" + code);
                } else {
                    setDefaultSpeakParams();
                }
            }
        });
        aiuiManager = AIUIManager.createInstance(context);
    }


    private void setDefaultSpeakParams() {
        setEngineType(this.mEngineType);
        this.speechSynthesizer.setParameter(SpeechConstant.STREAM_TYPE, "3");
        this.speechSynthesizer.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
    }


    public void setEngineType(String type) {
        if (type.equals(SpeechConstant.TYPE_CLOUD)) {
            mEngineType = SpeechConstant.TYPE_CLOUD;
        } else {
            mEngineType = SpeechConstant.TYPE_LOCAL;
        }
        this.speechSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
    }

    public void setGlobalSpeakListener(ISpeakListener mGlobalSpeakListener) {
        this.mGlobalSpeakListener = mGlobalSpeakListener;
    }

    public void setSpeakListener(ISpeakListener listener) {
        this.lastStartSpeakListener = this.startSpeakListener;
        this.startSpeakListener = listener;
    }

    @Override
    protected void requestTextUnderstand(String text, boolean isChainUnderstand) {
        Executors.newCachedThreadPool().execute(() -> {
            if (aiuiManager != null) {
                aiuiManager.startTextNlp(text, new IAIUIListener() {
                    @Override
                    public void onResult(String result) {
                        if (!TextUtils.isEmpty(result)) {
                            NLPResult nlpResult = new NLPResult(result);
                            onEngineResult(new EngineResult(nlpResult.getIflyAnswer(), EngineResult.ENGINE_IFLY));
                        } else {
                            if (isChainUnderstand) {
                                nextEngineChainTextUnderstand(text);
                            }
                        }
                    }
                });
            }
        });
    }

    public void startIflySpeak(String text) {
        if (this.speechSynthesizer != null) {
            if (this.startSpeakListener != null) {
                this.startSpeakListener.onSpeakBegin(text);
            }
            if (this.mGlobalSpeakListener != null) {
                this.mGlobalSpeakListener.onSpeakBegin(text);
            }
            this.speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, this.voicer);
            this.speechSynthesizer.setParameter(SpeechConstant.SPEED, this.speed);
            this.speechSynthesizer.setParameter(SpeechConstant.PITCH, this.pitch);
            this.speechSynthesizer.setParameter(SpeechConstant.VOLUME, this.volume);
            this.speechSynthesizer.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
            this.speechSynthesizer.startSpeaking(text, mSynthesizerListener);
        }
    }

    public void stopSpeak() {
        if (this.speechSynthesizer != null && this.speechSynthesizer.isSpeaking()) {
            this.speechSynthesizer.stopSpeaking();
        }
    }

    public void pauseSpeak() {
        if (this.speechSynthesizer != null && this.speechSynthesizer.isSpeaking()) {
            this.speechSynthesizer.pauseSpeaking();
        }
    }

    public void resumeSpeak() {
        if (this.speechSynthesizer != null && this.speechSynthesizer.isSpeaking()) {
            this.speechSynthesizer.resumeSpeaking();
        }
    }

    public boolean isSpeaking() {
        return this.speechSynthesizer.isSpeaking();
    }

    public void setSpeakParams(String voicerName, int speed, int pitch, int volume) {
        if (!TextUtils.isEmpty(voicerName)) {
            this.speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, this.voicer);
        }
        if (speed >= 0 && speed <= 100) {
            this.speechSynthesizer.setParameter(SpeechConstant.SPEED, this.speed);
        }
        if (pitch >= 0 && pitch <= 100) {
            this.speechSynthesizer.setParameter(SpeechConstant.PITCH, this.pitch);
        }
        if (volume >= 0 && volume <= 100) {
            this.speechSynthesizer.setParameter(SpeechConstant.VOLUME, this.volume);
        }
    }

    public void setRecognizeListener(IRecognizeListener mRecognizerListener) {
        this.recognizeListener = mRecognizerListener;
    }

    public void startRecognize() {
        cancelRecognize();
        mRecogResults.clear();
        if (speechRecognizer != null) {

            speechRecognizer.setParameter(SpeechConstant.VAD_BOS, this.vad_bos);
            speechRecognizer.setParameter(SpeechConstant.VAD_EOS, this.vad_eos);
            speechRecognizer.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, this.speech_timeout);
            speechRecognizer.setParameter(SpeechConstant.NET_TIMEOUT, this.net_timeout);

            if (!TextUtils.isEmpty(this.pcm_path)) {
                speechRecognizer.setParameter("audio_format", "pcm");
                speechRecognizer.setParameter("asr_audio_path", Environment.getExternalStorageDirectory() + "/" + this.pcm_path + "/" + System.currentTimeMillis() + ".pcm");
            }

            int ret = speechRecognizer.startListening(this.mRecognizerListener);
            Log.e(TAG, "startRecognize....: " + ret);
        }

    }

    private RecognizerListener mRecognizerListener = new RecognizerListener() {
        public void onBeginOfSpeech() {
            if (recognizeListener != null) {
                recognizeListener.onBeginOfSpeech();
            }

        }

        public void onError(SpeechError error) {
            Log.v(TAG, "RecognizerListener onError: " + error.getErrorCode());
            if (recognizeListener != null) {
                recognizeListener.onError(error);
            }

        }

        public void onEndOfSpeech() {
            if (recognizeListener != null) {
                recognizeListener.onEndOfSpeech();
            }
        }

        public void onResult(RecognizerResult results, boolean isLast) {
            String txt = praseResult(results);
            if (isLast) {
                if (recognizeListener != null) {
                    recognizeListener.onResult(txt);
                }
                if (recognizeTextCallback != null) {
                    recognizeTextCallback.onRecognizeText(txt);
                }
            }
        }

        public void onVolumeChanged(int volume, byte[] data) {
            if (recognizeListener != null) {
                recognizeListener.onVolumeChanged(volume, data);
            }

        }

        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            Log.v(TAG, "RecognizerListener eventType：" + eventType);
            //语音识别结束和关闭语音识别会返回20001，
            if (eventType == 20001) {
                if (stopRecognizeFlag) {
                    stopRecognizeFlag = false;
                    return;
                }
                //一句话识别结束会停止语音识别，应重新开起语音识别
                startRecognize();
            }

        }
    };

    private boolean stopRecognizeFlag = false;

    public void stopRecognize() {
        if (speechRecognizer != null) {
            Log.e(TAG, "stopRecognize......");
            speechRecognizer.stopListening();
            stopRecognizeFlag = true;
        }

    }

    public void cancelRecognize() {
        if (speechRecognizer != null) {
            speechRecognizer.cancel();
        }

    }

    public boolean isRecognizing() {
        return speechRecognizer != null && speechRecognizer.isListening();
    }

    private void setDefaultRecognizeParam() {
        speechRecognizer.setParameter(SpeechConstant.PARAMS, null);
        speechRecognizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        speechRecognizer.setParameter(SpeechConstant.RESULT_TYPE, "json");
        if (this.s_language.equals("en_us")) {
            speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "en_us");
            speechRecognizer.setParameter(SpeechConstant.ACCENT, null);
        } else {
            speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
            speechRecognizer.setParameter(SpeechConstant.ACCENT, this.s_language);
        }

        speechRecognizer.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
        speechRecognizer.setParameter(SpeechConstant.ASR_PTT, "0");
        speechRecognizer.setParameter(SpeechConstant.SAMPLE_RATE, "16000");
    }

    public void setRecogParams(String language, int bos, int eos, int speechtimeout, int nettimeout, String pcmpath) {
        if (!TextUtils.isEmpty(language)) {
            this.s_language = language;
        }
        if (bos > 0) {
            this.vad_bos = Integer.toString(bos);
        }
        if (eos > 0) {
            this.vad_eos = Integer.toString(eos);
        }
        if (speechtimeout > 0) {
            this.speech_timeout = Integer.toString(speechtimeout);
        }
        if (nettimeout > 0) {
            this.net_timeout = Integer.toString(nettimeout);
        }
        if (!TextUtils.isEmpty(pcmpath)) {
            this.pcm_path = pcmpath;
        }

        speechRecognizer.setParameter(SpeechConstant.VAD_BOS, this.vad_bos);
        speechRecognizer.setParameter(SpeechConstant.VAD_EOS, this.vad_eos);
        speechRecognizer.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, this.speech_timeout);
        speechRecognizer.setParameter(SpeechConstant.NET_TIMEOUT, this.net_timeout);
        if (s_language.equals("en_us")) {
            speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "en_us");
            speechRecognizer.setParameter(SpeechConstant.ACCENT, null);
        } else {
            speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
            speechRecognizer.setParameter(SpeechConstant.ACCENT, this.s_language);
        }

    }

    private final SynthesizerListener mSynthesizerListener = new SynthesizerListener() {
        @Override
        public void onSpeakResumed() {
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
        }

        @Override
        public void onSpeakPaused() {
        }

        @Override
        public void onSpeakBegin() {
        }

        @Override
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
            Log.d(TAG, "SynthesizerListener error " + arg0 + " ,arg1:" + arg1 + " ,arg2:" + arg2);
            if (arg0 == 21002) {
                if (IflyEngine.this.lastStartSpeakListener != null) {
                    IflyEngine.this.lastStartSpeakListener.onInterrupted();
                }

                if (IflyEngine.this.mGlobalSpeakListener != null) {
                    IflyEngine.this.mGlobalSpeakListener.onInterrupted();
                }
            }
        }

        @Override
        public void onCompleted(SpeechError errorCode) {

            if (IflyEngine.this.lastStartSpeakListener != null) {
                IflyEngine.this.lastStartSpeakListener.onSpeakOver(errorCode == null ? 0 : errorCode.getErrorCode());
            }

            if (IflyEngine.this.mGlobalSpeakListener != null) {
                IflyEngine.this.mGlobalSpeakListener.onSpeakOver(errorCode == null ? 0 : errorCode.getErrorCode());
            }

        }

        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
        }
    };


    private String praseResult(RecognizerResult results) {
        //所有分词解析成一个完整句子
        String tex = JsonParser.parseIatResult(results.getResultString());
        String sn = null;  //第几句

        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        this.mRecogResults.put(sn, tex);
        StringBuilder resultBuffer = new StringBuilder();

        for (String key : mRecogResults.keySet()) {
            resultBuffer.append(mRecogResults.get(key));
        }

        return resultBuffer.toString();
    }

    public static class Builder {
        private BaseUnderstandingEngine engine;
        private String iflyAppID;
        private Context context;

        private String engineType;
        private String voicer;
        private int speed = -1;
        private int pitch = -1;
        private int volume = -1;
        private int speech_timeout = -1;
        private int net_timeout = -1;
        private String s_language;


        public Builder(Context context) {
            this.context = context.getApplicationContext();
        }

        public Builder setIflyAppID(String iflyAppID) {
            this.iflyAppID = iflyAppID;
            return this;
        }

        public Builder setNextEngine(BaseUnderstandingEngine engine) {
            this.engine = engine;
            return this;
        }

        public Builder setEngineType(String engineType) {
            this.engineType = engineType;
            return this;
        }

        public Builder setVoicer(String voicer) {
            this.voicer = voicer;
            return this;
        }

        public Builder setSpeed(int speed) {
            this.speed = speed;
            return this;
        }

        public Builder setPitch(int pitch) {
            this.pitch = pitch;
            return this;
        }

        public Builder setVolume(int volume) {
            this.volume = volume;
            return this;
        }


        public Builder setSpeechTimeout(int speech_timeout) {
            this.speech_timeout = speech_timeout;
            return this;
        }

        public Builder setNetTimeout(int net_timeout) {
            this.net_timeout = net_timeout;
            return this;
        }

        public Builder setLanguage(String language) {
            this.s_language = language;
            return this;
        }


        public IflyEngine build() {
            return new IflyEngine(this);
        }
    }


    @Override
    public void destoryEngine() {
        super.destoryEngine();
        Log.i(TAG, "destoryEngine: iflyengine.....");
        if (this.speechRecognizer != null) {
            if (this.speechRecognizer.isListening()) {
                this.speechRecognizer.stopListening();
            }

            this.speechRecognizer.destroy();
            this.speechRecognizer = null;
        }
        if (this.speechSynthesizer != null) {
            if (this.speechSynthesizer.isSpeaking()) {
                this.speechSynthesizer.stopSpeaking();
            }

            this.speechSynthesizer.destroy();
            this.speechSynthesizer = null;
        }
        if (this.aiuiManager != null) {
            this.aiuiManager.destroyAgent();
            this.aiuiManager = null;
        }
    }


}
